﻿#include <wx/stattext.h>
#include "Board.h"
#include"MyFrame.h"
#include "Menu.h"

Board::Board(wxPanel* parent)
    : wxPanel(parent, -1, wxPoint(-1, -1), wxSize(2000, -1), wxBORDER_SUNKEN)
{
    SetBackgroundColour(wxColour(245, 244, 239));
    m_parent = parent;
    nowable = false;
    now = nullptr;
    
    Bind(wxEVT_LEFT_DOWN, &Board::OnMouse, this);
    Bind(wxEVT_LEFT_UP, &Board::OnMouse, this);
    Bind(wxEVT_MOTION, &Board::OnMouse, this);
    Bind(wxEVT_PAINT, &Board::OnPaint, this);
    Bind(wxEVT_RIGHT_DOWN, &Board::Search, this);
    Bind(wxEVT_MOUSEWHEEL, &Board::OnMouseWheel, this);
    
    timer = new wxTimer(this, wxID_ANY);
    // 绑定定时器事件处理函数
    timer->Start(4);
    st1 = new wxStaticText(this, -1, wxT(""), wxPoint(10, 10));   //  show the position (x: and y:)
    st2 = new wxStaticText(this, -1, wxT(""), wxPoint(10, 30));
    Bind(wxEVT_TIMER, &Board::OnTimer, this);

    SetBackgroundStyle(wxBG_STYLE_PAINT);
}

void Board::Clear() {
    nowable = false;
    now = nullptr;
    draws.clear();
    startP = wxPoint(0, 0);
    endP = wxPoint(0, 0);
    pointnum = 0;
    Refresh();

}

void Board::Back() {
    if (draws[draws.size() - 1]["type"] == "point") {
        pointnum--;
    }
    if(!draws.empty()) draws.pop_back();
    
    now = nullptr;
    startP = wxPoint(0,0);
    endP = wxPoint(0, 0);
    Refresh();
}

void Board::OnTimer(wxTimerEvent& event) {
    // 刷新窗口Refresh();
    st1->SetLabel(wxString::Format(wxT("x: %d"), Pos.x));
    st2->SetLabel(wxString::Format(wxT("y: %d"), Pos.y));
    
}

void Board::OnMouse(wxMouseEvent& event)
{
    Pos = event.GetPosition();
    wxPoint pos = event.GetPosition();
    int snapX = (pos.x / 10) * 10;
    int snapY = (pos.y / 10) * 10;


    if (event.LeftDown())
    {
        isdraw = true;
        startP.x = snapX;
        startP.y = snapY;
    }
    else if (event.LeftUp())
    {
        endP.x = snapX;
        endP.y = snapY;
        
        JsonAdd(startP, endP);
        startP.x = 0;
        startP.y = 0;
        endP.x = 0;
        endP.y = 0;

        // 停止定时器timer->Stop(); 
        isdraw = false;
        Refresh();
        
    }
    else if (event.LeftIsDown() && event.Dragging())
    {
       
        MyFrame* myframe = (MyFrame*)m_parent->GetParent();
        int flag = myframe->m_mu->flag;
        nowable = true;

        if (now != nullptr && flag == ID_SELECT) Move(pos);

        endP = pos;
        
        //timer->Start(4);
        Refresh();
    }

}



void Board::OnMouseWheel(wxMouseEvent& mouseEvent)
{
    wxPoint pos = mouseEvent.GetPosition();
    centerP = pos;
    // 获取滚轮滚动方向和距离
    int delta = mouseEvent.GetWheelRotation();
    int lines = mouseEvent.GetWheelDelta() / mouseEvent.GetWheelDelta();

    // 根据滚动方向和距离调整缩放比例
    if (delta > 0)
    {
        zoomFactor *= 1.1 * lines;  // 缩小画布
    }
    else
    {
        zoomFactor /= 1.1 * lines;  // 放大画布
    }

    Refresh();
}

void Board::JsonAdd(wxPoint startP, wxPoint endP) {
    MyFrame* myframe = (MyFrame*)m_parent->GetParent();
    int flag = myframe->m_mu->flag;
    Json::Value draw;

    wxColor pencolor = myframe->m_mu->pencolor;
    wxColor brushcolor = myframe->m_mu->brushcolor;

    draw["pcrgb"] = pencolor.GetRGB();
    if (brushcolor != -1)
        draw["bcrgb"] = brushcolor.GetRGB();
    else
        draw["bcrgb"] = -1;

    draw["pensize"] = 2;
    hasline = false;
    for (int i = 0; i < draws.size(); ++i)
    {
        if (draws[i]["type"] == "line") {
            hasline = true;
            break;
        }
           
    }
    if (hasline == true || flag != ID_POINT) {
        switch (flag)
        {
        case ID_LINE:
            draw["type"] = "line";
            draw["startx"] = centerP.x - ((centerP.x - startP.x) / zoomFactor);
            draw["starty"] = centerP.y - ((centerP.y - startP.y) / zoomFactor);
            draw["endx"] = centerP.x - ((centerP.x - endP.x) / zoomFactor);
            draw["endy"] = centerP.y - ((centerP.y - endP.y) / zoomFactor);
            draws.push_back(draw);
            break;
        case ID_RECT:
            draw["type"] = "rect";
            draw["startx"] = centerP.x - (centerP.x - (startP.x < endP.x ? startP.x : endP.x)) / zoomFactor;
            draw["starty"] = centerP.y - (centerP.y - (startP.y < endP.y ? startP.y : endP.y)) / zoomFactor;
            draw["width"] = abs(startP.x - endP.x) / zoomFactor;
            draw["height"] = abs(startP.y - endP.y) / zoomFactor;
            draws.push_back(draw);
            break;
        case ID_ROUD:
            draw["type"] = "roud";
            draw["centerx"] = ((centerP.x - ((centerP.x - startP.x) / zoomFactor)) + (centerP.x - ((centerP.x - endP.x) / zoomFactor))) / 2;
            draw["centery"] = ((centerP.y - ((centerP.y - startP.y) / zoomFactor)) + (centerP.y - ((centerP.y - endP.y) / zoomFactor))) / 2;
            draw["r"] = pow(pow((startP.x - endP.x), 2) + pow((startP.y - endP.y), 2), 0.5) / 2 / zoomFactor;
            draws.push_back(draw);
            break;
        case ID_ARC:
            draw["type"] = "arc";
            draw["startx"] = centerP.x - (centerP.x - (startP.x < endP.x ? startP.x : endP.x)) / zoomFactor;
            draw["starty"] = centerP.y - (centerP.y - (startP.y < endP.y ? startP.y : endP.y)) / zoomFactor;
            draw["width"] = abs(startP.x - endP.x) / zoomFactor;
            draw["height"] = abs(startP.y - endP.y) / zoomFactor;
            draw["sangle"] = 0;
            draw["eangle"] = 180;
            draws.push_back(draw);
            break;
        case ID_POINT:
            pointnum++;
            draw["type"] = "point";
            draw["num"] = pointnum;
            draw["connect"] = false;
            draw["centerx"] = centerP.x - (centerP.x - startP.x) / zoomFactor;
            draw["centery"] = centerP.y - (centerP.y - startP.y) / zoomFactor;
            draw["r"] = 2;
            draws.push_back(draw);
            break;
        default:
            break;
        }
    }
   
}

void Board::Move(wxPoint pos)
{
    int dx = pos.x - endP.x;
    int dy = pos.y - endP.y;

    if ((*now)["type"] == "line")
    {
        (*now)["startx"] = (*now)["startx"].asInt() + dx;
        (*now)["starty"] = (*now)["starty"].asInt() + dy;
        (*now)["endx"] = (*now)["endx"].asInt() + dx;
        (*now)["endy"] = (*now)["endy"].asInt() + dy;
    }
    else if ((*now)["type"] == "rect")
    {
        (*now)["startx"] = (*now)["startx"].asInt() + dx;
        (*now)["starty"] = (*now)["starty"].asInt() + dy;
    }
    else if ((*now)["type"] == "roud")
    {
        (*now)["centerx"] = (*now)["centerx"].asInt() + dx;
        (*now)["centery"] = (*now)["centery"].asInt() + dy;
    }
    else if ((*now)["type"] == "arc")
    {
        (*now)["startx"] = (*now)["startx"].asInt() + dx;
        (*now)["starty"] = (*now)["starty"].asInt() + dy;
    }
    
}

void Board::Delete() {
    if (now == NULL) return;
    std::vector<Json::Value> copy;

    auto it = draws.begin();
    for(int i = 0; it != draws.end(); i++,it++) {
        if (now != &draws[i]){
            copy.push_back(*it);
        }
    }
    now = NULL;
    draws = copy;
    Refresh();
    return;
}

void Board::Copy() {
    if (now == NULL) return;
    std::vector<Json::Value> copy;

    auto it = draws.begin();
    for (int i = 0; it != draws.end(); i++, it++) {
        if (now == &draws[i]) {
            copy.push_back(*it);
        }
        copy.push_back(*it);
    }
    draws = copy;
    Refresh();
    return;
}


void Board::OnPaint(wxPaintEvent& event)
{
    
    wxAutoBufferedPaintDC dc(this);

    dc.SetBackground(*wxWHITE_BRUSH);
    dc.Clear();
    
    // 创建位图缓冲区
    wxMemoryDC memDC;
    wxBitmap bufferBitmap(GetClientSize());
    
    memDC.SelectObject(bufferBitmap);
    memDC.SetBackground(*wxWHITE_BRUSH);
    memDC.Clear();

    // 在内存上下文中进行绘图操作
    wxBufferedDC bufferedDc(&memDC);

    wxPen pen(wxColour(235, 235, 235), 1);  // 网格线的颜色和宽度
    memDC.SetPen(pen);
    for (int x = 0; x < GetClientSize().GetWidth(); x += 10)
    {
        memDC.DrawLine(centerP.x - (centerP.x - x) * zoomFactor, centerP.y - (centerP.y - 0) * zoomFactor, centerP.x - (centerP.x - x) * zoomFactor, centerP.y - (centerP.y - GetClientSize().GetHeight()) * zoomFactor);
    }
    for (int y = 0; y < GetClientSize().GetHeight(); y += 10)
    {
        memDC.DrawLine(centerP.x - (centerP.x - 0) * zoomFactor, centerP.y - (centerP.y - y) * zoomFactor, centerP.x - (centerP.x - GetClientSize().GetWidth()) * zoomFactor, centerP.y - (centerP.y - y) * zoomFactor);
    }

    if(nowable == true)
    {
        MyFrame* myframe = (MyFrame*)m_parent->GetParent();
        int flag = myframe->m_mu->flag;
        wxColor pencolor = myframe->m_mu->pencolor;
        int pensize = 2;
        wxPen pen(pencolor, pensize * zoomFactor); // 创建画笔
        memDC.SetPen(pen); // 设置画笔

        wxColor brushcolor;
        if (myframe->m_mu->brushcolor == -1)//设置刷子
            memDC.SetBrush(*wxTRANSPARENT_BRUSH);
        else
        {
            brushcolor = myframe->m_mu->brushcolor;
            wxBrush brush(brushcolor);
            memDC.SetBrush(brush);
        }
        if (isdraw == true) {
           

            switch (flag) {
            case ID_LINE:
                memDC.DrawLine(startP, endP);
                break;
            case ID_RECT:
                _paintrect(startP, endP, memDC);
                break;
            case ID_ROUD:
                _paintroud(startP, endP, memDC);
                break;
            case ID_ARC:
                _paintarc(startP, endP, memDC);
                break;
            case ID_POINT:
                memDC.DrawCircle(startP, 2 * zoomFactor);
                break;
            default:
                break;
            }
        }

        for (int i = 0; i < draws.size(); ++i)
        {
            pencolor.SetRGB(draws[i]["pcrgb"].asInt());
            pensize = draws[i]["pensize"].asInt()*zoomFactor;
            wxPen pen2(pencolor, pensize);
            memDC.SetPen(pen2);

            if (draws[i]["bcrgb"].asInt() == -1)//设置刷子
                memDC.SetBrush(*wxTRANSPARENT_BRUSH);
            else
            {
                brushcolor.SetRGB(draws[i]["bcrgb"].asInt());
                wxBrush brush(brushcolor);
                memDC.SetBrush(brush);
            }

            if (draws[i]["type"] == "line")
                memDC.DrawLine(centerP.x - (centerP.x - draws[i]["startx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["starty"].asInt()) * zoomFactor,
                    centerP.x - (centerP.x - draws[i]["endx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["endy"].asInt()) * zoomFactor);
            else if(draws[i]["type"] == "rect")
                memDC.DrawRectangle(centerP.x - (centerP.x - draws[i]["startx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["starty"].asInt()) * zoomFactor,
                    draws[i]["width"].asInt() * zoomFactor, draws[i]["height"].asInt() * zoomFactor);
            else if(draws[i]["type"] == "roud")
                memDC.DrawCircle(centerP.x - (centerP.x - draws[i]["centerx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["centery"].asInt()) * zoomFactor, draws[i]["r"].asInt() * zoomFactor);
            else if(draws[i]["type"] == "arc")
                memDC.DrawEllipticArc(centerP.x - (centerP.x - draws[i]["startx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["starty"].asInt()) * zoomFactor,
                    draws[i]["width"].asInt() * zoomFactor, draws[i]["height"].asInt() * zoomFactor, 0, 180);
            else if (draws[i]["type"] == "point")
                memDC.DrawCircle(centerP.x - (centerP.x - draws[i]["centerx"].asInt()) * zoomFactor, centerP.y - (centerP.y - draws[i]["centery"].asInt()) * zoomFactor, 2 * zoomFactor);
        }
    }
    // 绘制完成后将缓冲区的图像复制到真正的设备上下文中进行显示
    dc.Blit(0, 0, GetClientSize().GetWidth(), GetClientSize().GetHeight(), &memDC, 0, 0);

}

void Board::_paintrect(wxPoint startP, wxPoint endP, wxMemoryDC& dc) {
    wxPoint s, e;
    s.x = startP.x < endP.x ? startP.x : endP.x;
    s.y = startP.y < endP.y ? startP.y : endP.y;
    e.x = startP.x > endP.x ? startP.x : endP.x;
    e.y = startP.y > endP.y ? startP.y : endP.y;
    wxSize sz = { e.x - s.x, e.y - s.y };
    dc.DrawRectangle(s, sz);
}

void Board::_paintroud(wxPoint startP, wxPoint endP, wxMemoryDC& dc) {
    int x = (startP.x + endP.x) / 2;
    int y = (startP.y + endP.y) / 2;
    int r = pow(pow((startP.x - endP.x), 2) + pow((startP.y - endP.y), 2), 0.5)/2;
    dc.DrawCircle(x, y, r);
}

void Board::_paintarc(wxPoint startP, wxPoint endP, wxMemoryDC& dc) {
    wxPoint s, e;
    s.x = startP.x < endP.x ? startP.x : endP.x;
    s.y = startP.y < endP.y ? startP.y : endP.y;
    e.x = startP.x > endP.x ? startP.x : endP.x;
    e.y = startP.y > endP.y ? startP.y : endP.y;
    dc.DrawEllipticArc(s.x,s.y, e.x - s.x, e.y - s.y,0,180);
}

void Board::Search(wxMouseEvent& event) {
    MyFrame* myframe = (MyFrame*)m_parent->GetParent();
    int flag = myframe->m_mu->flag;

    if (flag != ID_SELECT) return;

    wxPoint pos = event.GetPosition();
    wxPoint s, e;

    for (int i = 0; i < draws.size(); ++i)
    {
        if (draws[i]["type"] == "line")
        {
            s = { draws[i]["startx"].asInt(),draws[i]["starty"].asInt() };
            e = { draws[i]["endx"].asInt(),draws[i]["endy"].asInt() };
            int d = 10;//选择直线时允许的偏离度
            if( ((pos.x - s.x) * (pos.x - e.x) <= 0) &&
                (abs((s.y - pos.y)*(e.x-pos.x) -(e.y-pos.y)* (s.x-pos.x)) <= d*(abs(s.x - e.x) + abs(s.y - e.y)) / 2))
            {
                /*wxString msg = wxString::Format("Mouse position: %d, %d", clientPos.x, clientPos.y);
                wxMessageBox(msg, "Information", wxOK | wxICON_INFORMATION);*/
                now = &draws[i];
                goto a1;
            }
        }
        else if (draws[i]["type"] == "rect")
        {
            s = { draws[i]["startx"].asInt(),draws[i]["starty"].asInt() };
            if ((pos.x >= s.x)&&(pos.y >= s.y)&&(pos.x <= s.x + draws[i]["width"].asInt()) && (pos.y <= s.y + draws[i]["height"].asInt()))
            {
                now = &draws[i];
                goto a1;
            }
        }
        else if (draws[i]["type"] == "roud")
        {
            if(pow(pow((pos.x - draws[i]["centerx"].asInt()), 2) + pow((pos.y - draws[i]["centery"].asInt()), 2), 0.5) <= draws[i]["r"].asInt())
            {
                now = &draws[i];
                goto a1;
                
            }
        }
        else if (draws[i]["type"] == "arc")
        {
            s = { draws[i]["startx"].asInt(),draws[i]["starty"].asInt() };
            if ((pos.x >= s.x) && (pos.y >= s.y) && (pos.x <= s.x + draws[i]["width"].asInt()) && (pos.y <= s.y + draws[i]["height"].asInt()))
            {
                now = &draws[i];
                goto a1;
            }
        }
    }
    now = nullptr;
a1:
    endP = pos;
    return;
}
